/*
 * Object   : MySimMgr
 * Type     : UI
 *
 * Narrator : Kamran H. Khan 
 * Email    : KAMRANHK@gmail.com
 * 
 * Copyleft : Attribution - CreativeCommons http://creativecommons.org/licenses/by-nc/3.0/
 *            This software is provided 'as-is', without any express or implied warranty.
 *            In no event will the author(s) be held liable for any damages arising from
 *            the use of this software.
 * 
 *            Permission is granted to anyone to use this software for any purpose,
 *            including commercial applications, and to alter it and redistribute it
 *            freely, subject to the following restrictions:
 * 
 *            1. The origin of this software must not be misrepresented; you must not
 *            claim that you wrote the original software. If you use this software
 *            in a product, an acknowledgment in the product documentation would be
 *            appreciated but is not required.
 * 
 *            2. Altered source versions must be plainly marked as such, and must not
 *            be misrepresented as being the original software.
 * 
 *            3. This notice may not be removed or altered from any source distribution.
 * 
 * Description: 
 * Handles the xml file, basically reading.
 * 
 * 
 * Revision History:
 * 
 * Date(MMM/dd/yy)      Owner           Description
 * ----------------------------------------------------------------------------------------------------------------------------------------------
 * Oct/24/08            Kamran H. Khan  Added skeleton code
 * Oct/25/08            Kamran H. Khan  Added more methods
 * Dec/02/08            Kamran H. Khan  Added support of multiple message types
 *                                      - Fixed names for transaction code tag and message type tag
 *                                      - Added support for non delimited text message
 * Feb/20/09            Kamran H. Khan  Added server response functionality. See known bug KB09.
 * 
 * 
 * 
*/


using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using Maxima.Help;
using Maxima.Common;

namespace Maxima.MySimMgr
{
    public class CSimHandler
    {
        private int TRANCODE_POSITION = 4; //zero based index
        private string TRANCODE_FIELDNAME = "Transaction Code";
        private string MESSAGETYPE_FIELDNAME = "Message Type";
        private bool m_bResponseAble = false;
        private string m_strXmlFilename = string.Empty;

        public string XmlFilename
        {
            get { return m_strXmlFilename; }
        }

        private string m_strXsdFilename = string.Empty;
        XmlDocument m_theXmlDoc = null;
        private string m_strCurrentSimulator = string.Empty;
        public string SimulatorName
        {
            get { return m_strCurrentSimulator; }
            set { m_strCurrentSimulator = value; }
        }


        private string m_strCurrentTransaction = string.Empty;
        public string TransactionName
        {
            get { return m_strCurrentTransaction; }
            set { m_strCurrentTransaction = value; }
        }

        private string m_strTransactionCode = string.Empty;
        public string TransactionCode
        {

            get { return m_strTransactionCode; }
        }
        private string m_strIP;
        public string IP
        {
            get { return m_strIP; }
        }

        private int m_nPort;
        public int Port
        {
            get { return m_nPort; }
        }
        private string m_strSeparator;

        private bool m_bDelimited;
        public bool IsDelimited
        {
            get { return m_bDelimited; }
        }

        private string m_strRequestCode;
        public string RequestCode
        {
            get { return m_strRequestCode; }
        }

        private string m_strResponseCode;
        public string ResponseCode
        {
            get { return m_strResponseCode; }
        }

        private bool m_bServer;
        public bool IsServer
        {
            get { return m_bServer; }
        }

        private int m_nMetaLength;
        private string m_strMetaType;
        private string m_strDataFormat;


        /// <summary>
        /// Initializes a new instance of the <see cref="CMySimMgr"/> class.
        /// </summary>
        /// <param name="strXmlFilePath">The STR XML file path.</param>
        public CSimHandler(string strXmlFilePath)
        {
            m_strXmlFilename = strXmlFilePath;
            InitObject();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CMySimMgr"/> class.
        /// </summary>
        public CSimHandler()
        {
        }

        /// <summary>
        /// Inits the object.
        /// </summary>
        private void InitObject()
        {
            m_theXmlDoc = new XmlDocument();
            m_theXmlDoc.Load(m_strXmlFilename);
        }

        /// <summary>
        /// Loads the simulations.
        /// </summary>
        /// <returns></returns>
        private List<string> LoadSimulations()
        {
            return GetNodes(m_theXmlDoc.DocumentElement, "Simulator", true);
        }

        /// <summary>
        /// Loads all simulations.
        /// </summary>
        /// <param name="strXmlFilename">The STR XML filename.</param>
        /// <returns></returns>
        public List<string> LoadAllSimulations(string strXmlFilename)
        {
            m_theXmlDoc = null;
            m_theXmlDoc = new XmlDocument();

            m_strXmlFilename = strXmlFilename;
            try
            {
                m_theXmlDoc.Load(strXmlFilename);

            }
            catch (Exception exc)
            {
                CHelper.Log("Invalid file. " + exc.Message);
                return null;
            }
            return LoadSimulations();
        }

        /// <summary>
        /// Gets the nodes.
        /// </summary>
        /// <param name="theNodes">The nodes.</param>
        /// <param name="strNodeName">Name of the STR node.</param>
        /// <param name="bMultipleOccurances">if set to <c>true</c> [b multiple occurances].</param>
        /// <returns></returns>
        private List<string> GetNodes(XmlNode theNodes, string strNodeName, bool bMultipleOccurances)
        {
            List<string> lstItems = new List<string>();

            foreach (XmlNode thisNode in theNodes.SelectNodes(strNodeName))
            {
                lstItems.Add(thisNode.Attributes["Name"].Value.ToString());
                if (!bMultipleOccurances)
                    break;
            }

            return lstItems;
        }

        /// <summary>
        /// Loads all transactions.
        /// </summary>
        /// <param name="strSimulator">The STR simulator.</param>
        /// <returns></returns>
        public List<string> LoadAllTransactions(string strSimulator)
        {
            List<string> lstItems = new List<string>();
            foreach (XmlNode theSimulator in m_theXmlDoc.DocumentElement.SelectNodes("Simulator"))
            {
                if (theSimulator.Attributes["Name"].Value.ToString() == strSimulator)
                {
                    lstItems = GetNodes(theSimulator, "Transaction", true);
                }
            }

            return lstItems;
        }

        private string m_strHeaderMsg;
        public string Header
        {
            get { return m_strHeaderMsg; }
        }

        private string m_strRequestMsg;
        public string RequestMsg
        {
            get { return m_strRequestMsg; }
        }

        private string m_strResponseMsg;
        public string ResponseMsg
        {
            get { return m_strResponseMsg; }
        }

        /// <summary>
        /// Loads the this transaction.
        /// </summary>
        /// <param name="nTranCode">The n tran code.</param>
        public void LoadTransactionByCode(string nTranCode)
        {
            CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Inside");
            //CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Trying to load this transaction");
            string strTranCode = nTranCode.ToString().PadLeft(2, '0');
            m_strTransactionCode = strTranCode;

            //Get transaction code
            string strXQuery = "/MySimulations/Simulator[@Name='" + m_strCurrentSimulator + "']/Transaction[@Code='" + strTranCode + "']";
            try
            {
                m_strCurrentTransaction = m_theXmlDoc.SelectSingleNode(strXQuery).Attributes["Name"].Value.ToString();


                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Found current transaction:"+ m_strCurrentTransaction);

                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Loading basic transacton");
                LoadTransaction();
            }
            catch (Exception exc)
            {
                CLogger.GetInstance().Debug(this.GetType().Name, System.Reflection.Emit.MethodBuilder.GetCurrentMethod().Name, "Couldnt find transaction by code:"+ m_strTransactionCode);
            }

        }

        /// <summary>
        /// Loads the this transaction.
        /// </summary>
        /// <param name="strTransactionName">Name of the STR transaction.</param>
        public void LoadTransactionByName(string strTransactionName)
        {
            m_strCurrentTransaction = strTransactionName;

            //Get transaction code
            string strXQuery = "/MySimulations/Simulator[@Name='" + m_strCurrentSimulator + "']/Transaction[@Name='" + m_strCurrentTransaction + "']";
            m_strTransactionCode = m_theXmlDoc.SelectSingleNode(strXQuery).Attributes["Code"].Value.ToString();

            LoadTransaction();

        }

        private void LoadTransaction()
        {
            GetSimulatorAttributes();//Gets the simulator attributes

            if (!m_bResponseAble)
            {
                //Add header only if its a request message.
                m_strHeaderMsg = GetHeader("Header");
            }
            m_strRequestMsg = GetMessage("Request");
            m_strResponseMsg = GetMessage("Response");

            //string strFullMessage = m_strHeaderMsg + m_strRequestMsg;

            m_strRequestMsg = m_strHeaderMsg + m_strRequestMsg;
            m_strResponseMsg = m_strHeaderMsg + m_strResponseMsg;

            string strMetaLengthRequest = string.Empty;
            string strMetaLengthResponse = string.Empty;
            //STEP 2. Apply meta length

            switch (m_strMetaType)
            {
                case "Meta.Txt":
                    strMetaLengthRequest = m_strRequestMsg.Length.ToString().PadLeft(m_nMetaLength, '0');
                    strMetaLengthResponse = m_strResponseMsg.Length.ToString().PadLeft(m_nMetaLength, '0');
                    break;

                case "Meta.Bin":
                    strMetaLengthRequest = GetMetaLengthBin(m_strRequestMsg.Length).ToString().PadLeft(m_nMetaLength, '0');
                    strMetaLengthResponse = GetMetaLengthBin(m_strResponseMsg.Length).ToString().PadLeft(m_nMetaLength, '0');
                    break;

                case "Meta.Hex": break;
                case "Meta.Oct": break;
                default: break;
            }

            m_strRequestMsg = strMetaLengthRequest + m_strRequestMsg;
            m_strResponseMsg = strMetaLengthResponse + m_strResponseMsg;
            m_strResponseMsg = m_strResponseMsg.Replace(m_strRequestCode, m_strResponseCode);

            ApplyMessageFormatting(); //Change the data format, for instance to hex, binary, oct, ascii, etc.


            //GetSimulatorAttributes();//Gets the simulator attributes

            //m_strHeaderMsg = GetHeader("Header");
            //m_strRequestMsg = GetMessage("Request");
            //m_strResponseMsg = GetMessage("Response");

            ////string strFullMessage = m_strHeaderMsg + m_strRequestMsg;

            //m_strRequestMsg = m_strHeaderMsg + m_strRequestMsg;
            //m_strResponseMsg = m_strHeaderMsg + m_strResponseMsg;

            //string strMetaLengthRequest = string.Empty;
            //string strMetaLengthResponse = string.Empty;
            ////STEP 2. Apply meta length

            //switch (m_strMetaType)
            //{
            //    case "Meta.Txt":
            //        strMetaLengthRequest = m_strRequestMsg.Length.ToString().PadLeft(m_nMetaLength, '0');
            //        strMetaLengthResponse = m_strResponseMsg.Length.ToString().PadLeft(m_nMetaLength, '0');
            //        break;

            //    case "Meta.Bin":
            //        strMetaLengthRequest = GetMetaLengthBin(m_strRequestMsg.Length);
            //        strMetaLengthResponse = GetMetaLengthBin(m_strResponseMsg.Length);
            //        break;

            //    case "Meta.Hex": break;
            //    case "Meta.Oct": break;
            //    case "Meta.None": break; //do nothing.
            //    default: break;
            //}

            //m_strRequestMsg = strMetaLengthRequest + m_strRequestMsg;
            //m_strResponseMsg = strMetaLengthResponse + m_strResponseMsg;
            //m_strResponseMsg = m_strResponseMsg.Replace(m_strRequestCode, m_strResponseCode);

            //ApplyMessageFormatting();
        }



        private void ApplyMessageFormatting()
        {
            switch (m_strDataFormat.ToUpper())
            {
                case "FORMAT.HEX": //Conver to hex
                    m_strRequestMsg = CHelper.StringToHex(m_strRequestMsg).ToUpper();
                    m_strResponseMsg = CHelper.StringToHex(m_strResponseMsg).ToUpper();
                    break;
                //case "FORMAT.TXT":
                //    m_strRequestMsg = CHelper.StringToHex(m_strRequestMsg);
                //    m_strResponseMsg = CHelper.StringToHex(m_strResponseMsg);
                //    break;
                //case "FORMAT.BIN":
                //    m_strRequestMsg = CHelper.StringToHex(m_strRequestMsg);
                //    m_strResponseMsg = CHelper.StringToHex(m_strResponseMsg);
                //    break;
                default: break;
            }

        }

        /// <summary>
        /// Gets the simulator attributes.
        /// </summary>
        private void GetSimulatorAttributes()
        {
            //Load simulator properties
            string strXQuery = "/MySimulations/Simulator[@Name='" + m_strCurrentSimulator + "']";
            XmlNodeList ndsFields = m_theXmlDoc.SelectNodes(strXQuery);

            if (ndsFields.Count == 0)
                return;// string.Empty;

            string strConcatenatedData = string.Empty;
            foreach (XmlNode thisNode in ndsFields)
            {
                try
                {
                    m_strIP = thisNode.Attributes["IP"].Value.ToString();
                    m_nPort = Convert.ToInt32(thisNode.Attributes["Port"].Value.ToString());
                    m_bServer = Convert.ToBoolean(thisNode.Attributes["server"].Value.ToString());
                    m_nMetaLength = Convert.ToInt32(thisNode.Attributes["MetaLength"].Value.ToString());
                    m_strMetaType = thisNode.Attributes["MetaType"].Value.ToString();
                    m_strSeparator = thisNode.Attributes["Separator"].Value.ToString();
                    m_bDelimited = Convert.ToBoolean(thisNode.Attributes["Delimited"].Value.ToString());
                    m_strRequestCode = thisNode.Attributes["RequestCode"].Value.ToString();
                    m_strResponseCode = thisNode.Attributes["ResponseCode"].Value.ToString();
                    m_strDataFormat = thisNode.Attributes["DataFormat"].Value.ToString();
                }
                catch (Exception exc)
                {
                    CHelper.Log("CMySimMgr::GetSimulatorAttributes\t|Problem getting a tag\t| " + exc.Message);
                }
            }

        }

        /// <summary>
        /// Gets the message.
        /// </summary>
        /// <param name="strMsgType">Type of the STR MSG.</param>
        /// <returns></returns>
        private string GetMessage(string strMsgType)
        {
            //Get message details
            string strXQuery = "/MySimulations/Simulator[@Name='" + m_strCurrentSimulator + "']/Transaction[@Name='" + m_strCurrentTransaction + "']" + "/" + strMsgType + "/Field";

            XmlNodeList ndsFields = m_theXmlDoc.SelectNodes(strXQuery);
            if (ndsFields.Count == 0)
                return string.Empty;

            string strConcatenatedData = string.Empty;
            foreach (XmlNode thisNode in ndsFields)
            {
                strConcatenatedData += ProcessData(thisNode);
            }

            return strConcatenatedData;

        }


        /// <summary>
        /// Gets the header.
        /// </summary>
        /// <param name="strMsgType">Type of the STR MSG.</param>
        /// <returns></returns>
        private string GetHeader(string strMsgType)
        {
            //XPath query
            string strXQuery = "/MySimulations/Simulator[@Name='" + m_strCurrentSimulator + "']/Header/Field";

            XmlNodeList ndsFields = m_theXmlDoc.SelectNodes(strXQuery);
            if (ndsFields.Count == 0)
                return string.Empty;

            string strConcatenatedData = string.Empty;
            foreach (XmlNode thisNode in ndsFields)
            {
                strConcatenatedData += ProcessData(thisNode);
            }

            return strConcatenatedData;

        }

        /// <summary>
        /// Processes the data.
        /// </summary>
        /// <param name="thisNode">The this node.</param>
        /// <returns></returns>
        private string ProcessData(XmlNode thisNode)
        {
            //if(thisNode == null)
            string strName = thisNode.Attributes["Name"].Value.ToString();
            string strValue = thisNode.InnerText.ToString();

            int nLength = Convert.ToInt32(thisNode.Attributes["Length"].Value.ToString());
            bool bShouldAutoPad = Convert.ToBoolean(thisNode.Attributes["AutoPad"].Value.ToString());
            bool bPadRight = Convert.ToBoolean(thisNode.Attributes["PadRight"].Value.ToString());
            char chPadChar = Convert.ToChar(thisNode.Attributes["PadChar"].Value.ToString());
            string strDataType = thisNode.Attributes["DataType"].Value.ToString();
            string strData = thisNode.InnerText.ToString();

            switch (strDataType.ToUpper())
            {
                case "TYPE.DATE":

                    switch (nLength)
                    {
                        case 8://yyyymmdd
                            strData = DateTime.Now.ToString("yyyyMMdd");
                            break;
                        case 14://CCYYMMDDHHMMSS
                            strData = DateTime.Now.ToString("yyyyMMddhhmmss");
                            break;
                        default:
                            strData = DateTime.Now.ToString(strData);
                            if (strData.Length > nLength)
                            {
                                strData = strData.Substring(0, nLength);
                            }
                            break;
                    }
                    break;
                case "TYPE.TIME":

                    strData = DateTime.Now.ToString("hhmmss");
                    break;
                case "TYPE.NUMBER":

                    if (bShouldAutoPad)
                    {
                        if (bPadRight)
                            strData = strData.PadRight(nLength, chPadChar);
                        else
                            strData = strData.PadLeft(nLength, chPadChar);
                    }

                    break;
                case "TYPE.AUTONUMBER":

                    if (bShouldAutoPad)
                    {
                        if (bPadRight)
                            strData = GetAutoNumber(strData).Substring(0, nLength).PadRight(nLength, chPadChar);
                        else
                            strData = GetAutoNumber(strData).Substring(0, nLength).PadLeft(nLength, chPadChar);
                    }

                    break;


                case "TYPE.STRING":

                    if (bShouldAutoPad)
                    {
                        if (bPadRight)
                            strData = strData.PadRight(nLength, chPadChar);
                        else
                            strData = strData.PadLeft(nLength, chPadChar);
                    }

                    break;
                default:
                    CHelper.Log("Unknown data type found. [" + strDataType + "]");
                    break;
            }

            if (strName.Equals("Transaction Code"))
            {
                strData = m_strTransactionCode;
            }

            //STEP 1. Apply separator if its delimited
            if (m_bDelimited)
            {
                strData += m_strSeparator;
            }

            return strData;
        }

        /// <summary>
        /// Gets the auto number.
        /// </summary>
        /// <param name="strSeed">The STR seed.</param>
        /// <returns></returns>
        private string GetAutoNumber(string strSeed)
        {
            string strRandomNumber = string.Empty;

            if (strSeed == null || strSeed == "" || strSeed.Length > 6)
            {
                strRandomNumber = DateTime.Now.Ticks.ToString().Substring(DateTime.Now.Ticks.ToString().Length - 7, 6);
                strRandomNumber = strRandomNumber + DateTime.Now.Ticks.ToString().Substring(DateTime.Now.Ticks.ToString().Length - 7, 6);

            }
            else
            {
                strRandomNumber = (new Random(Convert.ToInt32(strSeed))).Next().ToString();
            }
            return strRandomNumber;
        }

        /// <summary>
        /// Replaces the specified STR data.
        /// </summary>
        /// <param name="strData">The STR data.</param>
        /// <param name="nGoto">The n goto.</param>
        /// <param name="nInsertBytes">The n insert bytes.</param>
        /// <param name="strDesiredValue">The STR desired value.</param>
        /// <returns></returns>
        private string Replace(string strData, int nGoto, int nInsertBytes, string strDesiredValue)
        {
            strData = strData.Remove(/*Skip to*/nGoto, /*Remove one byte*/nInsertBytes); //Remove second
            strData = strData.Insert(nGoto, strDesiredValue);

            return strData;
        }

        ///// <summary>
        ///// Gets the meta length bin.
        ///// </summary>
        ///// <param name="nDataLength">Length of the n data.</param>
        ///// <returns></returns>
        //private string GetMetaLengthBin(int nDataLength)
        //{
        //    //Steps to calculate the meta length in characters
        //    //STEP 1: Get the div part. Divide data length by 256 - //int nPartDiv = nDataLength / 256;
        //    //STEP 2: Get the Modulus part. Take modulus of Data length by 256 - //int nPartMod = nDataLength % 256;
        //    //STEP 3: Convert into characters, concat and return. //Convert.ToChar(nPartDiv).ToString() + Convert.ToChar(nPartMod).ToString();

        //    string strLengthInChars = string.Empty;
        //    strLengthInChars = Convert.ToChar((nDataLength / 256)).ToString() + Convert.ToChar((nDataLength % 256)).ToString();

        //    return strLengthInChars;
        //}


        /// <summary>
        /// Gets the meta length bin.
        /// </summary>
        /// <param name="nDataLength">Length of the n data.</param>
        /// <returns></returns>
        private static string GetMetaLengthBin(int nDataLength)
        {
            //Steps to calculate the meta length in characters
            //STEP 1: Get the div part. Divide data length by 256 - //int nPartDiv = nDataLength / 256;
            //STEP 2: Get the Modulus part. Take modulus of Data length by 256 - //int nPartMod = nDataLength % 256;
            //STEP 3: Convert into characters, concat and return. //Convert.ToChar(nPartDiv).ToString() + Convert.ToChar(nPartMod).ToString();

            string strLengthInChars = string.Empty;
            int nPartDiv = nDataLength / 256;
            int nPartMod = nDataLength % 256;
            char chDiv = Convert.ToChar(nPartDiv);
            char chMod = Convert.ToChar(nPartMod);

            //chDiv = Convert.ToChar(chDiv.ToString().Replace("\0", "0"));
            strLengthInChars = chDiv.ToString() + chMod.ToString();

            //strLengthInChars = Convert.ToChar((nDataLength / 256)).ToString() + Convert.ToChar((nDataLength % 256)).ToString();
            //string str = BinaryToString(strLengthInChars);

            return strLengthInChars;
        }

        /// <summary>
        /// Generates the sample XML.
        /// </summary>
        /// <returns></returns>
        public string GenerateSampleXml()
        {
            string m_strSampleXmlFilePath = "Temp-MySim9-" + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + ".xml";
            string strSampleXml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- MySim9 - Simulator Software v1.0 --><!-- MySim9 - Simulator Configuration File --><!-- Copyleft (r) 2008-09 MaximaLabs Solutions --><MySimulations><!-- Simulators --><Simulator Name=\"IVR\" server=\"false\" IP=\"127.0.0.1\" Port=\"3000\" MetaLength=\"4\" MetaType=\"Meta.Txt\" Separator=\"|\" DataFormat = \"Format.Hex\" Delimited=\"true\" RequestCode=\"0200\" ResponseCode=\"0210\" ><!-- Message Header --><Header><Field Name=\"Message Type\" DataType =\"Type.String\" Length=\"4\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">0200</Field><Field Name=\"Transaction Code\" DataType =\"Type.String\" Length=\"3\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">000</Field><!--  Transmission Date and time created by the IVR and it will be generated for each call --><Field Name=\"Transmission Date and Time\" DataType =\"Type.Date\" Length=\"10\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">ddMMhhmmss</Field><!--  6 Digit Random Number generated by delivery channel --><Field Name=\"STAN\" DataType =\"Type.AutoNumber\" Length=\"6\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">5555</Field><Field Name=\"Customer Identification\" DataType =\"Type.String\" Length=\"13\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">NIC</Field><Field Name=\"Message Protocol\" DataType =\"Type.String\" Length=\"2\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">01</Field></Header><!--  Message Header END --><!--  Transactions --><Transaction Code=\"02\" Name=\"TPIN Validation\"><Request><Field Name=\"Field1\" DataType =\"Type.String\" Length=\"16\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">DESEncryptedTPIN</Field></Request><Response><Field Name=\"ResponseCode\" DataType =\"Type.Number\" Length=\"3\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">000</Field></Response></Transaction><Transaction Code=\"50\" Name=\"ATM PIN Validation\"><Request><Field Name=\"Field1\" DataType =\"Type.String\" Length=\"16\" AutoPad=\"false\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">DESEncryptedTPIN</Field></Request><Response><Field Name=\"ResponseCode\" DataType =\"Type.Number\" Length=\"3\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">000</Field></Response></Transaction><Transaction Code=\"11\" Name=\"Customer Demographics Debit Card\"><Request><!-- This message contains only header --></Request><Response><Field Name=\"ResponseCode\" DataType =\"Type.Number\" Length=\"3\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">000</Field><Field Name=\"Field11\" DataType =\"Type.String\" Length=\"13\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">123123123</Field><Field Name=\"Field12\" DataType =\"Type.String\" Length=\"10\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">Test name</Field><Field Name=\"Field13\" DataType =\"Type.String\" Length=\"2\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">00</Field><Field Name=\"Field14\" DataType =\"Type.String\" Length=\"2\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">00</Field><Field Name=\"Field15\" DataType =\"Type.String\" Length=\"2\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" ExtractFromRequest=\"false\">00</Field></Response></Transaction><!-- Transactions END --></Simulator><!-- Simulators END--></MySimulations>";
            //"<!-- MySim9 - Simulator Software v1.0 --><!-- MySim9 - Simulator Configuration File --><!-- Copyleft (r) 2008-09 MaximaLabs Solutions --><?xml version=\"1.0\" encoding=\"utf-8\"?><MySimulations><!-- Simulators --><Simulator Name=\"IVR\" server=\"false\" IP=\"127.0.0.1\" Port=\"3000\" MetaLength=\"4\" MetaType=\"Meta.Txt\" Separator=\"|\" Delimited=\"true\" RequestCode=\"0200\" ResponseCode=\"0210\"><!-- Message Header --><Header><Field Name=\"Message Type\" DataType =\"Type.String\" Length=\"4\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >0200</Field><Field Name=\"Transaction Code\" DataType =\"Type.String\" Length=\"3\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >000</Field><!--  Transmission Date and time created by the IVR and it will be generated for each call --><Field Name=\"Transmission Date and Time\" DataType =\"Type.Date\" Length=\"10\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >ddMMhhmmss</Field><!--  6 Digit Random Number generated by delivery channel --><Field Name=\"STAN\" DataType =\"Type.AutoNumber\" Length=\"6\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >5555</Field><Field Name=\"Customer Identification\" DataType =\"Type.String\" Length=\"13\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >NIC</Field><Field Name=\"Message Protocol\" DataType =\"Type.String\" Length=\"2\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >01</Field></Header><!--  Message Header END --><!--  Transactions --><Transaction Code=\"02\" Name=\"TPIN Validation\"><Request><Field Name=\"Field1\" DataType =\"Type.String\" Length=\"16\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >DESEncryptedTPIN</Field></Request><Response><Field Name=\"ResponseCode\" DataType =\"Type.Number\" Length=\"3\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >000</Field></Response></Transaction><Transaction Code=\"50\" Name=\"ATM PIN Validation\"><Request><Field Name=\"Field1\" DataType =\"Type.String\" Length=\"16\" AutoPad=\"false\" PadRight =\"true\" PadChar =\"0\" >DESEncryptedTPIN</Field></Request><Response><Field Name=\"ResponseCode\" DataType =\"Type.Number\" Length=\"3\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >000</Field></Response></Transaction><Transaction Code=\"11\" Name=\"Customer Demographics Debit Card\"><Request><!-- This message contains only header --></Request><Response><Field Name=\"ResponseCode\" DataType =\"Type.Number\" Length=\"3\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >000</Field><Field Name=\"Field11\" DataType =\"Type.String\" Length=\"13\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >123123123</Field><Field Name=\"Field12\" DataType =\"Type.String\" Length=\"10\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >Test name</Field><Field Name=\"Field13\" DataType =\"Type.String\" Length=\"2\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >00</Field><Field Name=\"Field14\" DataType =\"Type.String\" Length=\"2\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >00</Field><Field Name=\"Field15\" DataType =\"Type.String\" Length=\"2\" AutoPad=\"true\" PadRight =\"true\" PadChar =\"0\" >00</Field></Response></Transaction><!-- Transactions END --></Simulator><!-- Simulators END--></MySimulations>";
            using (StreamWriter theTempFile = new StreamWriter(m_strSampleXmlFilePath))
            {
                theTempFile.WriteLine(strSampleXml);
            }

            return m_strSampleXmlFilePath;
        }

        /// <summary>
        /// Processes the this message.
        /// </summary>
        /// <param name="strData">The STR data.</param>
        /// <returns></returns>
        internal bool TranslateThisMessage(string strData)
        {
            bool bStatus = false;

            try
            {
                //This shall parse the message and check if its a 0200 message,
                //and would prepare and send a response accordingly.

                //STEP 1: Get the 
                int nSkipTag = strData.IndexOf("]");
                string strMsg = strData.Substring(nSkipTag + 1, strData.Length - nSkipTag - 1);
                string strTranCode = string.Empty;


                int nPosition = 0;// -1;
                m_bResponseAble = IsResponseAbleMsg(strData);

                if (m_bDelimited)
                {
                    if (!m_bResponseAble)
                    {
                        bStatus = false; //lets not respond because 0210 is itself is a response. return.
                    }
                    else
                    {
                        nPosition = GetTranCodePosition();

                        string[] strValues = strMsg.Split(m_strSeparator.ToCharArray());
                        strTranCode = strValues[nPosition];

                        LoadTransactionByCode(strTranCode);
                        bStatus = true;
                    }
                }
                else
                {
                    if (!m_bResponseAble)
                    {
                        bStatus = false;
                    }
                    else
                    {
                        //STEP 2: Look for transaction code position in the xml file, and then get the trancode value from that position
                        //          out of the strData
                        ///////////////////////////////////////////////////////////////


                        string strXQuery = "/MySimulations/Simulator[@Name='" + m_strCurrentSimulator + "']/Header/Field";
                        int nLength = 0;
                        nPosition += nSkipTag + 1 + m_nMetaLength; //Position = Skip [IP:Port] tag + meta length padding


                        //Look for the transaction code position
                        foreach (XmlNode thisNode in m_theXmlDoc.SelectNodes(strXQuery))
                        {
                            //Check if this node is the trancode
                            if (thisNode.Attributes["Name"].Value.ToString().StartsWith(TRANCODE_FIELDNAME))
                            {
                                //Yes it is, Get the length of the trancode that would be read.
                                nLength = Convert.ToInt32(thisNode.Attributes["Length"].Value.ToString()); //Add field length
                                break;
                            }
                            else
                            {
                                //Add field length
                                nPosition += Convert.ToInt32(thisNode.Attributes["Length"].Value.ToString());
                            }
                        }


                        ////////////////////////////////

                        strTranCode = strData.Substring(nPosition, nLength); //Get the trancode
                        LoadTransactionByCode(strTranCode);//Load this transaction
                        bStatus = true; //Loaded successfully
                    }
                }
            }
            catch (Exception exc) { bStatus = false; CHelper.Log("Couldnt process this message. Error: " + exc.Message); }

            return bStatus;

        }

        private bool IsResponseAbleMsg(string strData)
        {
            if (strData == null || strData.Equals(""))
                return false;

            bool bStatus = false;

            int nRead = strData.IndexOf("]");
            string strMsg = strData.Substring(nRead + 1, strData.Length - nRead - 1);


            if (m_bDelimited)
            {
                //Parse using delimitations
                string[] strValues = strMsg.Split(m_strSeparator.ToCharArray());

                //Prepare XPath query to get all the fields.
                string strXQuery = "/MySimulations/Simulator[@Name='" + m_strCurrentSimulator + "']/Header/Field";

                //- Separate method
                int nPosition = 0;

                //Look for the field position for message type
                foreach (XmlNode thisNode in m_theXmlDoc.SelectNodes(strXQuery))
                {
                    if (thisNode.Attributes["Name"].Value.ToString().StartsWith(MESSAGETYPE_FIELDNAME))
                        break;//This is the right position, lets break;
                    else
                    {
                        //Look for next position
                        nPosition++;
                    }
                }
                //- 

                //- Look for the 0200ish message types 
                if (!strValues[nPosition].Contains("0200"))
                {
                    bStatus = false; //lets not respond because 0210 is itself is a response. return.
                }
                else
                {
                    bStatus = true; //Yes, the message contains the 0200, so its a request! now we'd prepare response.
                }
            }
            else
            {
                //No delimitations, parse text.
                //The message format is not delimited. Lets looks for the message type (0200) and transaction code

                //STEP 1: Look for message type, send response (goto step 2)if its 0200 type of message.
                //STEP 2: Look for transaction code
                //STEP 3: Prepare response
                //STEP 4: Concat desination information
                //STEP 5: Send response

                //Message format shall be like: [IP:PORT][MESSAGE RESPONSE]

                //STEP 1: look for the position of the message type, and check that position in the attributes list.
                string strXQuery = "/MySimulations/Simulator[@Name='" + m_strCurrentSimulator + "']/Header/Field";//[@Name='" + MESSAGETYPE_FIELDNAME + "']";
                string strMsgType = string.Empty;

                //bool bResponseAble = LookForRequestHeader();
                int nLength = 0;

                ////////////////////////////////////////////
                int nPosition = 0;
                nPosition = nRead + 1 + m_nMetaLength; //Message padding

                foreach (XmlNode thisNode in m_theXmlDoc.SelectNodes(strXQuery))
                {
                    if (thisNode.Attributes["Name"].Value.ToString().StartsWith(MESSAGETYPE_FIELDNAME))
                    {
                        nLength = Convert.ToInt32(thisNode.Attributes["Length"].Value.ToString());
                        break;
                    }
                    else
                    {
                        //nPosition++;
                        nPosition += Convert.ToInt32(thisNode.Attributes["Length"].Value.ToString()); //Add field length
                        strMsgType = strData.Substring(0, nPosition);
                    }
                }

                //////////////////////////////
                //Find the position at which the transaction code resides.

                strMsgType = strData.Substring(nPosition, nLength);//position at which the message type resides

                //Respond only if the message type is 0200ish

                //Check the third bit, which tells the message type, request=0 or response=1
                //if (strMsgType.Equals("0200"))
                if (strMsgType[2].ToString() == "0") // third bit is 0, 02[0]0
                {
                    bStatus = true;
                }
                else
                {
                    bStatus = false;
                }

                ///////////////////////////////////////
            }

            return bStatus;
        }

        private int GetMessageTypePosition()
        {
            string strXQuery = "/MySimulations/Simulator[@Name='" + m_strCurrentSimulator + "']/Header/Field";

            int nPosition = 0;
            nPosition += m_nMetaLength; //Message padding

            foreach (XmlNode thisNode in m_theXmlDoc.SelectNodes(strXQuery))
            {
                if (thisNode.Attributes["Name"].Value.ToString().StartsWith(MESSAGETYPE_FIELDNAME))
                    break;
                else
                {
                    nPosition++;
                    nPosition += thisNode.Attributes["Name"].Value.ToString().Length; //Add field length
                }
            }

            return nPosition;
        }


        /// <summary>
        /// Gets the tran code position.
        /// </summary>
        /// <returns></returns>
        private int GetTranCodePosition()
        {
            int nPosition = 0;
            string strXQuery = "/MySimulations/Simulator[@Name='" + m_strCurrentSimulator + "']/Header/Field";

            foreach (XmlNode thisNode in m_theXmlDoc.SelectNodes(strXQuery))
            {
                if (thisNode.Attributes["Name"].Value.ToString().StartsWith(TRANCODE_FIELDNAME))
                    break;
                nPosition++;
            }

            return nPosition;
        }

    }
}
